/**
 * @method Queue 数组队列解决方案
 * @author Lkx
 *
 * @method config 配置参数
 * @method data   手动入队
 * @method clear  手动出队
 */

(function (factory) {

  if (typeof exports === "object" && typeof module !== "undefined") {
    module.exports = factory();
  } else {
    window.Kxui.queue = window.kxui.queue = factory();
  }

}(function () {

  "use strict";

  const win = window;
  const Kxui = win.Kxui;
  const method = Kxui.method;

  // 全局错误样式
  // 通过主入口注册，达到全模块统一错误输出
  const Kxui_throws_style = win.Kxui_throws_style;

  /**
   * @method 异常抛出
   * @param  {number} num       抛出错误文案的编号
   * @param  {string} name      抛出错误的方法
   * @param  {string} parameter 抛出错误的参数
   * @param  {string} info      其他说明信息
   */
  const throws = (num, name, parameter, info) => {
    if (Kxui.configuration.debug) {
      const nums = {};
      nums[0] = `依赖模块 {${parameter}} 未被提前加载`;
      nums[1] = `配置参数 {${parameter}} 为空或数据类型错误，正确数据类型应为 {${info}}`;
      nums[2] = `使用方法 {${name}} 前需先执行 {config} 进行配置，并确认 {iden} 是否匹配`;
      console.error(`%cKxui.queue${name ? `.${name}` : ""}%c (${Kxui.about.version})\n%c${nums[num]}，请检查修改。`, Kxui_throws_style[0], Kxui_throws_style[1], Kxui_throws_style[2]);
    }
  };

  // 前置依赖判断
  // 判断当前模块是否前置依赖均加载完毕
  const pre_dependence = () => {
    if (method) {
      return true;
    } else {
      throws(0, "", "method");
      return false;
    }
  };

  class Load {

    constructor(parameter) {
      this.iden = method.data(parameter.iden, "string") ? parameter.iden : "default";

      // 只有在使用 config 时才进行相关字段声明
      if (parameter.type === "config") {
        let queue = {};
        queue.data = [];
        queue.duration = method.data(parameter.duration, "number") ? parameter.duration : false;
        queue.length = method.data(parameter.length, "number") ? parameter.length : 10;
        method.sto_cache_set(`[kxui/queue/${this.iden}]`, queue);
      }

      // 出入队共同
      else {
        this.callback = method.data(parameter.callback, "function") ? parameter.callback : false;

        // 前置参数判断
        let cache = method.sto_cache_get(`[kxui/queue/${this.iden}]`) || {};
        if (!method.data(cache.data)) {
          throws(2, parameter.type);
        } else if (!this.callback) {
          throws(1, parameter.type, "callback", "function");
        } else {

          // 手动入队
          if (parameter.type === "data") {
            if (!method.data(parameter.data) || method.data(parameter.data, "function")) {
              throws(1, parameter.type, "data", "非函数");
            } else {
              this.sort = method.data(parameter.sort, "boolean") ? parameter.sort : true;
              this.dataPush(cache, parameter);
            }
          }

          // 手动出队
          else if (parameter.type === "clear") {
            if (method.data(parameter.index) && !method.data(parameter.index, "number")) {
              throws(1, parameter.type, "index", "number");
            } else {
              this.dataClear(cache, parameter);
            }
          }
        }
      }
    }

    /**
     * @method 手动入队
     * @param  {object} cache     数组队列缓存
     * @param  {object} parameter 数组队列参数
     *
     * 判断是否达到了队列最大长度
     * 若是没有达到最大长度则直接进行入队
     * 若是达到了最大长度，将会执行一次出队操作
     */
    dataPush(cache, parameter) {
      if (cache.data.length >= cache.length) { cache.data[this.sort ? "shift" : "pop"](); }

      // 在入队数据中打入标记
      let id = +method.num_random(1000, 9999);
      let pushData = {id: id, value: parameter.data };
      cache.data[this.sort ? "push" : "unshift"](pushData);
      method.sto_cache_set(`[kxui/queue/${this.iden}]`, cache);

      // 执行函数回调
      this.callback_handle(cache.data);

      // 执行自动出队
      this.autoClear(id, cache.duration);
    }

    /**
     * @method 手动出队
     * @param  {object} cache     数组队列缓存
     * @param  {object} parameter 数组队列参数
     *
     * 判断是否传入需要出队的数据
     * 若是不存在则进行清空或移除队列操作
     * 存在存在出队的数据只移除对应的数据
     */
    dataClear(cache, parameter) {
      const is_remove = method.data(parameter.remove, "boolean") ? parameter.remove : false;

      // 出队指定数据
      if (!is_remove && method.data(parameter.index)) {
        cache.data = method.arr_del_ele(cache.data, parameter.index, false);
        method.sto_cache_set(`[kxui/queue/${this.iden}]`, cache);
      }

      // 出队全部数据
      else {
        cache.data = [];
        if (is_remove) {
          method.sto_cache_del(`[kxui/queue/${this.iden}]`);
        } else {
          method.sto_cache_set(`[kxui/queue/${this.iden}]`, cache);
        }
      }

      // 执行函数回调
      this.callback_handle(cache.data);
    }

    /**
     * @method 执行自动出队
     * @param  {number} id       数据标记
     * @param  {number} duration 持续时间
     */
    autoClear(id, duration) {
      const autoClear = (shiftId, shiftDuration) => {
        setTimeout(() => {
          let data = [];
          let cacheData = method.sto_cache_get(`[kxui/queue/${this.iden}]`) || {};
          for (let i = 0; i < cacheData.data.length; i++) {
            if (cacheData.data[i].id !== shiftId) { data.push(cacheData.data[i]); }
          }

          // 重新赋值数据
          cacheData.data = data;
          method.sto_cache_set(`[kxui/queue/${this.iden}]`, cacheData);

          // 执行函数回调
          this.callback_handle(cacheData.data);
        }, shiftDuration);
      };

      // 判断是否存在自动出队时间
      // 若是存在将执行自动出队计时器，将当前标记的进行移除队列
      if (duration) {
        autoClear(id, duration);
      }
    }

    /**
     * @method 回调处理
     * @param  {object} data 数据队列
     *
     * 赛选出真实数据进行回调
     */
    callback_handle(data) {
      let arr = [];
      for (let i = 0; i < data.length; i++) { arr.push(data[i].value); }
      this.callback(arr);
    }
  }

  class Queue {

    constructor() {
      this.name = "Queue";
      this.info = "Array Queue Solution";
    }

    /**
     * @method 配置参数
     * @param  {object} parameter 数组队列参数
     *
     * Queue.config(parameter)
     */
    config(parameter = {}) {
      if (pre_dependence()) {
        parameter.type = "config";
        new Load(parameter);
      }
    }

    /**
     * @method 手动入队
     * @param  {*} parameter 数组队列参数
     *
     * Queue.data(parameter)
     */
    data(parameter = {}) {
      if (pre_dependence()) {
        parameter.type = "data";
        new Load(parameter);
      }
    }

    /**
     * @method 手动出队
     * @param  {*} parameter 数组队列参数
     *
     * Queue.clear(parameter)
     */
    clear(parameter = {}) {
      if (pre_dependence()) {
        parameter.type = "clear";
        new Load(parameter);
      }
    }
  }

  return new Queue();

}));
